package com.hb.gp.util.tools;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.hb.gp.util.BytesToInt;
import com.hb.gp.util.MsgGenUtil;
import com.hb.gp.util.ShareParam;

/**
 * 
 * @author duanxd 2014-12-4 liuhh 加入　token
 * 
 */
public class CapUtil {

	private byte[] capHeader = null;
	private int capHeaderLen = 0;
	private byte[] capDirectory = null;
	private int capDirectoryLen = 0;
	private byte[] capImport = null;
	private int capImportLen = 0;
	private byte[] capApplet = null;
	private int capAppletLen = 0;
	private byte[] capClass = null;
	private int capClassLen = 0;
	private byte[] capMethod = null;
	private int capMethodLen = 0;
	private byte[] capStaticField = null;
	private int capStaticFieldLen = 0;
	private byte[] capConstantPool = null;
	private int capConstantPoolLen = 0;
	private byte[] capRefLocation = null;
	private int capRefLocationLen = 0;
	private byte[] capExport = null;
	private int capExportLen = 0;
	private String fileId = null;
	private String appletId = null;

	public void getComp(byte[] cap) {
		int offset = 0;
		// int flag = 0;
		int tag = 0;
		// byte[] buf = new byte[1024];
		byte[] fileLen = new byte[2];
		int fileNameLen = 0;
		int fileNameLenEx = 0;
		byte[] bytezipedsize = new byte[4];
		byte[] tmp = new byte[4];
		byte[] tmp2 = new byte[2];
		int zipedsize = 0;
		// int allOffset = 0;
		int cmpLen = 0;
		byte[] flagDw = new byte[4];
		byte[] compMothed = new byte[2];
		while (offset < cap.length) {
			// offset = 0;
			this.read(cap, flagDw, offset, 4);
			// System.out.println( "flagDw :" + MsgGenUtil.buf2hex(flagDw));
			offset += 8;
			this.read(cap, compMothed, offset, 2);
			// System.out.println( "compMothed :" +
			// MsgGenUtil.buf2hex(compMothed));

			offset += 10;// 18

			this.read(cap, bytezipedsize, offset, 4);
			for (int i = 3; i >= 0; i--) {
				tmp[i] = bytezipedsize[3 - i];
			}

			offset += 8;// 26
			zipedsize = MsgGenUtil.makeInt(tmp);
			System.out.println(" bytezipedsize: " + zipedsize);
			this.read(cap, fileLen, offset, 2);
			for (int i = 1; i >= 0; i--) {
				tmp2[i] = fileLen[1 - i];
			}
			fileNameLen = MsgGenUtil.makeInt(tmp2);
			// System.out.println(" fileNameLen: " + fileNameLen);

			offset += 2;// 28

			this.read(cap, fileLen, offset, 2);

			for (int i = 1; i >= 0; i--) {
				tmp2[i] = fileLen[1 - i];
			}
			fileNameLenEx = MsgGenUtil.makeInt(tmp2);
			// System.out.println(" fileNameLenEx: " + fileNameLenEx);
			offset = offset + 2 + fileNameLen + fileNameLenEx;

			tag = cap[offset];
			offset += 1;
			this.read(cap, fileLen, offset, 2);

			offset += 2;

			for (int i = 1; i >= 0; i--) {
				tmp2[i] = bytezipedsize[1 - i];
			}
			cmpLen = MsgGenUtil.makeInt(tmp2);
			// System.out.println(" cmpLen: " + cmpLen);
			offset -= 3;
			int compFlat = MsgGenUtil.makeInt(compMothed);
			if (compFlat == 0) {
				switch (tag) {
				case 1: // capHeader
					capHeader = new byte[cmpLen];
					capHeaderLen = cmpLen;
					this.read(cap, capHeader, offset, cmpLen);
					// System.out.println("capHeader: " +
					// MsgGenUtil.buf2hex(capHeader));
					break;
				case 2: // capDirectory
					capDirectory = new byte[cmpLen];
					capDirectoryLen = cmpLen;
					this.read(cap, capDirectory, offset, cmpLen);
					// System.out.println("capDirectory: " +
					// MsgGenUtil.buf2hex(capDirectory));
					break;
				case 3: // capApplet
					capApplet = new byte[cmpLen];
					capAppletLen = cmpLen;
					this.read(cap, capApplet, offset, cmpLen);
					// System.out.println("capApplet: " +
					// MsgGenUtil.buf2hex(capApplet));
					break;
				case 4: // capImport
					capImport = new byte[cmpLen];
					capImportLen = cmpLen;
					this.read(cap, capImport, offset, cmpLen);
					// System.out.println("capImport: " +
					// MsgGenUtil.buf2hex(capImport));
					break;

				case 5: // capConstantPool
					capConstantPool = new byte[cmpLen];
					capConstantPoolLen = cmpLen;
					this.read(cap, capConstantPool, offset, cmpLen);
					// System.out.println("capConstantPool: " +
					// MsgGenUtil.buf2hex(capConstantPool));
					break;
				case 6: // capClass
					capClass = new byte[cmpLen];
					capClassLen = cmpLen;
					this.read(cap, capClass, offset, cmpLen);
					// System.out.println("capClass: " +
					// MsgGenUtil.buf2hex(capClass));
					break;
				case 7: // capMethod
					capMethod = new byte[cmpLen];
					capMethodLen = cmpLen;
					this.read(cap, capMethod, offset, cmpLen);
					// System.out.println("capMethod: " +
					// MsgGenUtil.buf2hex(capMethod));
					break;
				case 8: // capStaticField
					capStaticField = new byte[cmpLen];
					capStaticFieldLen = cmpLen;
					this.read(cap, capStaticField, offset, cmpLen);
					// System.out.println("capStaticField: " +
					// MsgGenUtil.buf2hex(capStaticField));
					break;

				case 9: // capRefLocation
					capRefLocation = new byte[cmpLen];
					capRefLocationLen = cmpLen;
					this.read(cap, capRefLocation, offset, cmpLen);
					// System.out.println("capRefLocation: " +
					// MsgGenUtil.buf2hex(capRefLocation));
					break;
				case 10: // capExport
					capExport = new byte[cmpLen];
					capExportLen = cmpLen;
					this.read(cap, capExport, offset, cmpLen);
					break;
				}
				offset += cmpLen;
			} else {
				offset = this.findNextCmp(cap, offset);
			}
			// System.out.println(" offset: " + offset);
		}

	}

	public List<String> doCap(String tcode, InputStream in,
			String pbCardKeyMacSk) throws IOException {

		int gMaxLen = 256; //
		List<String> result = new ArrayList<String>();
		byte[] capBuff = new byte[100 * 1024];// 存储50K的数据
		int len = in.read(capBuff);
		byte[] cap = new byte[len];
		System.arraycopy(capBuff, 0, cap, 0, len);
		// System.out.println(MsgGenUtil.buf2hex(cap));
		this.getComp(cap);
		int capSize = 0;
		capSize = capHeaderLen + capDirectoryLen + capImportLen + capAppletLen
				+ capClassLen + capMethodLen + capStaticFieldLen + capExportLen
				+ capConstantPoolLen + capRefLocationLen;
		String s0 = null;
		if (capSize < 128) {
			s0 = "C4" + MsgGenUtil.buf2hex(MsgGenUtil.Int2Bytes1(capSize));
		} else if (capSize < 256) {
			s0 = "C481" + MsgGenUtil.buf2hex(MsgGenUtil.Int2Bytes1(capSize));
		} else if (capSize < 65536) {
			s0 = "C482" + MsgGenUtil.buf2hex(MsgGenUtil.Int2Bytes2(capSize));
		} else {
			s0 = "C483" + MsgGenUtil.buf2hex(MsgGenUtil.Int2Bytes3(capSize));
		}
		StringBuffer capStrBuff = new StringBuffer(s0);
		if (capHeaderLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capHeader));
		}
		if (capDirectoryLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capDirectory));
		}
		if (capImportLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capImport));
		}
		if (capAppletLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capApplet));
		}
		if (capClassLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capClass));
		}
		if (capMethodLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capMethod));
		}
		if (capStaticFieldLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capStaticField));
		}
		if (capExportLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capExport));
		}
		if (capConstantPoolLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capConstantPool));
		}
		if (capRefLocationLen > 0) {
			capStrBuff.append(MsgGenUtil.buf2hex(capRefLocation));
		}
		String str0 = "84E800";
		int index = 0;
		int remain = 0;
		for (int i = 0; i < capStrBuff.length(); i += gMaxLen) {
			str0 = "84E800";
			if (i + gMaxLen >= capStrBuff.length()) {
				str0 = "84E880";
				remain = capStrBuff.length() - i;
				str0 = str0
						+ MsgGenUtil.buf2hex(MsgGenUtil.Int2Bytes1(index))
						+ MsgGenUtil.buf2hex(MsgGenUtil
								.Int2Bytes1(remain / 2 + 8));
				str0 = str0 + capStrBuff.substring(i, i + remain);
				ShareParam.GP_MAC.put(
						tcode,
						getIMac(str0, pbCardKeyMacSk,
								ShareParam.GP_MAC.get(tcode), true));
				str0 = str0 + ShareParam.GP_MAC.get(tcode);
			} else {
				str0 = str0
						+ MsgGenUtil.buf2hex(MsgGenUtil.Int2Bytes1(index))
						+ MsgGenUtil.buf2hex(MsgGenUtil
								.Int2Bytes1(gMaxLen / 2 + 8));
				str0 = str0 + capStrBuff.substring(i, i + gMaxLen);
				ShareParam.GP_MAC.put(
						tcode,
						getIMac(str0, pbCardKeyMacSk,
								ShareParam.GP_MAC.get(tcode), true));
				str0 = str0 + ShareParam.GP_MAC.get(tcode);
			}
			index += 1;
			result.add(str0);
		}

		int offset = 12;
		len = 1;
		len = this.getInt(capHeader, offset, len);
		byte[] fileIdTmp = new byte[len];
		offset += 1;
		System.arraycopy(capHeader, offset, fileIdTmp, 0, len);
		fileId = MsgGenUtil.buf2hex(fileIdTmp);
		System.out.println("fileid : " + fileId);

		if (capImportLen > 0) {
			System.out.println("capImport: " + MsgGenUtil.buf2hex(capImport));
			len = 1;
			offset = 4;
			len = this.getInt(capImport, offset, len);
			fileIdTmp = new byte[len];
			offset += 1;
			System.arraycopy(capImport, offset, fileIdTmp, 0, len);
			appletId = MsgGenUtil.buf2hex(fileIdTmp);
			System.out.println("appletId : " + appletId);
		}
		return result;
	}

	public String getIMac(String src, String key, String iv, boolean encryptflag) {
		MACGen macGen = new MACGen();
		// byte[] mac = macGen.genMAC(MsgGenUtil.BCD2Bytes(key),
		// MsgGenUtil.BCD2Bytes(src), MsgGenUtil.BCD2Bytes(iv),
		// encryptflag);
		byte[] sk_b = MsgGenUtil.BCD2Bytes(key);
		byte[] src_b = MsgGenUtil.BCD2Bytes(src);
		byte[] iv_b = MsgGenUtil.BCD2Bytes(iv);
		boolean flag=false;
		byte[] mac = macGen.genMAC(sk_b, src_b, iv_b, flag);
		return MsgGenUtil.buf2hex(mac);
	}

	private void read(byte[] src, byte[] obj, int offset, int len) {
		System.arraycopy(src, offset, obj, 0, len);
	}

	private int findNextCmp(byte[] cap, int offset) {
		int res = cap.length + 1;
		byte[] tmp = new byte[4];
		for (int j = offset; (j + 4) < cap.length; j++) {
			this.read(cap, tmp, j, 4);
			if (MsgGenUtil.buf2hex(tmp).equalsIgnoreCase("504B0304")) {
				res = j;
				break;
			}
		}
		return res;
	}

	// public static void main(String[] args){
	// CapUtil util = new CapUtil();
	// String fileName = "E:\\s@t\\applet_cap\\simplify.cap";
	// File file = new File(fileName);
	// try{
	// InputStream in = new FileInputStream(file);
	// List list = util.doCap(in);
	// for(int i = 0 ; i< list.size(); i ++){
	// String str = (String)list.get(i);
	// System.out.println(str);
	// }
	//
	// }
	// catch(Exception ex){
	// ex.printStackTrace();
	// }
	// }
	public int getInt(byte[] cmdParam, int offset, int len) {
		byte[] tmp = new byte[len];
		System.arraycopy(cmdParam, offset, tmp, 0, len);
		return BytesToInt.GetInt(tmp);
	}

	/**
	 * @return Returns the fileId.
	 */
	public String getFileId() {
		return fileId;
	}

	/**
	 * @return Returns the appletId.
	 */
	public String getAppletId() {
		return appletId;
	}
}
